package com.example.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;

/**
 * Redis配置类 - 支持单机和集群模式自动切换
 * @author Logan.Li
 */
@Slf4j
@Configuration
@EnableCaching
public class RedisConfig {

    // 集群配置
    @Value("${spring.redis.cluster.nodes:}")
    private String clusterNodes;
    
    @Value("${spring.redis.cluster.max-redirects:}")
    private String maxRedirectsStr;

    // 单机配置
    @Value("${spring.redis.host:}")
    private String host;
    
    @Value("${spring.redis.port:6379}")
    private int port;
    
    @Value("${spring.redis.database:0}")
    private int database;
    
    @Value("${spring.redis.password:}")
    private String password;

    /**
     * Redis连接工厂 - 启动时根据Nacos配置自动选择集群或单机模式
     * @author Logan.Li
     */
    @Bean
    @Primary
    public RedisConnectionFactory redisConnectionFactory() {
        log.info("=== Redis配置检测开始 ===");
        log.info("集群节点配置: {}", StringUtils.hasText(clusterNodes) ? clusterNodes : "未配置");
        log.info("单机主机配置: {}", StringUtils.hasText(host) ? host + ":" + port : "未配置");
        
        // 优先检测集群配置
        if (StringUtils.hasText(clusterNodes)) {
            log.info("✅ 检测到Redis集群配置，启用集群模式");
            return createClusterConnectionFactory();
        } 
        // 检测单机配置
        else if (StringUtils.hasText(host)) {
            log.info("✅ 检测到Redis单机配置，启用单机模式");
            return createStandaloneConnectionFactory();
        } 
        // 兜底：使用默认单机配置
        else {
            log.warn("⚠️ 未检测到Redis配置，使用默认单机模式: localhost:6379");
            log.warn("建议在Nacos中配置Redis连接信息");
            return createDefaultStandaloneConnectionFactory();
        }
    }

    /**
     * 创建集群连接工厂 - 支持阿里云Redis集群和自建Redis集群
     * @author Logan.Li
     */
    private RedisConnectionFactory createClusterConnectionFactory() {
        try {
            RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
            
            // 解析集群节点
            List<String> nodes = Arrays.asList(clusterNodes.split(","));
            log.info("解析Redis集群节点: {}", nodes);
            
            // 判断集群类型
            if (nodes.size() == 1) {
                log.info("检测到单节点集群配置（可能是阿里云Redis集群）: {}", nodes.get(0));
            } else {
                log.info("检测到多节点集群配置（自建Redis集群）: {} 个节点", nodes.size());
            }
            
            clusterConfiguration.setClusterNodes(nodes.stream()
                .map(node -> {
                    String[] parts = node.trim().split(":");
                    if (parts.length != 2) {
                        throw new IllegalArgumentException("Redis集群节点格式错误: " + node + "，正确格式: host:port");
                    }
                    return new org.springframework.data.redis.connection.RedisNode(parts[0], Integer.parseInt(parts[1]));
                })
                .collect(java.util.stream.Collectors.toList()));
            
            // 智能设置最大重定向次数
            int maxRedirects = calculateMaxRedirects(nodes.size());
            clusterConfiguration.setMaxRedirects(maxRedirects);
            log.info("Redis集群最大重定向次数: {} (节点数: {}, 自动计算)", maxRedirects, nodes.size());
            
            // 设置密码（如果有）
            if (StringUtils.hasText(password)) {
                clusterConfiguration.setPassword(password);
                log.info("Redis集群已设置密码认证");
            }
            
            log.info("✅ Redis集群连接工厂创建成功（支持阿里云和自建集群）");
            return new LettuceConnectionFactory(clusterConfiguration);
            
        } catch (Exception e) {
            log.error("❌ Redis集群连接工厂创建失败: {}", e.getMessage());
            throw new RuntimeException("Redis集群配置错误", e);
        }
    }

    /**
     * 创建单机连接工厂
     * @author Logan.Li
     */
    private RedisConnectionFactory createStandaloneConnectionFactory() {
        try {
            RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
            standaloneConfiguration.setHostName(host);
            standaloneConfiguration.setPort(port);
            standaloneConfiguration.setDatabase(database);
            
            log.info("Redis单机连接信息: {}:{}, 数据库: {}", host, port, database);
            
            // 设置密码（如果有）
            if (StringUtils.hasText(password)) {
                standaloneConfiguration.setPassword(password);
                log.info("Redis单机已设置密码认证");
            }
            
            log.info("✅ Redis单机连接工厂创建成功");
            return new LettuceConnectionFactory(standaloneConfiguration);
            
        } catch (Exception e) {
            log.error("❌ Redis单机连接工厂创建失败: {}", e.getMessage());
            throw new RuntimeException("Redis单机配置错误", e);
        }
    }

    /**
     * 创建默认单机连接工厂
     * @author Logan.Li
     */
    private RedisConnectionFactory createDefaultStandaloneConnectionFactory() {
        try {
            RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
            standaloneConfiguration.setHostName("localhost");
            standaloneConfiguration.setPort(6379);
            standaloneConfiguration.setDatabase(0);
            
            log.info("使用默认Redis单机连接: localhost:6379, 数据库: 0");
            log.info("✅ 默认Redis单机连接工厂创建成功");
            return new LettuceConnectionFactory(standaloneConfiguration);
            
        } catch (Exception e) {
            log.error("❌ 默认Redis单机连接工厂创建失败: {}", e.getMessage());
            throw new RuntimeException("默认Redis配置错误", e);
        }
    }

    /**
     * 智能计算Redis集群最大重定向次数
     * @param nodeCount 集群节点数量
     * @return 最大重定向次数
     * @author Logan.Li
     */
    private int calculateMaxRedirects(int nodeCount) {
        // 如果手动配置了重定向次数，优先使用配置值
        if (StringUtils.hasText(maxRedirectsStr)) {
            try {
                int configuredRedirects = Integer.parseInt(maxRedirectsStr.trim());
                log.info("使用手动配置的重定向次数: {}", configuredRedirects);
                return configuredRedirects;
            } catch (NumberFormatException e) {
                log.warn("重定向次数配置格式错误: {}, 将使用自动计算", maxRedirectsStr);
            }
        }
        
        // 自动计算重定向次数的策略
        int calculatedRedirects;
        if (nodeCount == 1) {
            // 阿里云等云服务Redis集群（单个访问地址）
            calculatedRedirects = 3;
            log.info("检测到云服务Redis集群（单地址），推荐重定向次数: {}", calculatedRedirects);
        } else if (nodeCount <= 3) {
            // 小型集群：3个节点以内
            calculatedRedirects = Math.max(3, nodeCount);
            log.info("检测到小型Redis集群，推荐重定向次数: {}", calculatedRedirects);
        } else if (nodeCount <= 6) {
            // 中型集群：4-6个节点
            calculatedRedirects = nodeCount;
            log.info("检测到中型Redis集群，推荐重定向次数: {}", calculatedRedirects);
        } else {
            // 大型集群：7个节点以上
            calculatedRedirects = Math.min(nodeCount, 10); // 最大不超过10次
            log.info("检测到大型Redis集群，推荐重定向次数: {} (限制最大10次)", calculatedRedirects);
        }
        
        return calculatedRedirects;
    }

    /**
     * 自定义RedisTemplate - 用于对象序列化
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 使用GenericJackson2JsonRedisSerializer来序列化和反序列化redis的value值
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        // Hash的key也采用StringRedisSerializer的序列化方式
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        // Hash的value也采用GenericJackson2JsonRedisSerializer的序列化方式
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}
